﻿using Fdb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Fdb
{
    /// <summary>
    /// 数据类映射器类
    /// </summary>
    public class DataClassMapper
    {
        /// <summary>
        /// 基础上下文对象
        /// </summary>
        public BaseDbContext BaseDbContext = new BaseDbContext();

        /// <summary>
        /// 数据库配置信息
        /// </summary>
        public DbInfo DbInfo = new DbInfo();

        /// <summary>
        /// 所有表
        /// </summary>
        public List<TableClass> TableList = new List<TableClass>();

        /// <summary>
        /// 参与context类生成的表序号集合
        /// </summary>
        public string ContextTbls = string.Empty;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="dbInfo"></param>
        public DataClassMapper(DbInfo dbInfo)
        {
            this.BaseDbContext = new BaseDbContext(CreateConnString(dbInfo));
            this.DbInfo = dbInfo;
            this.TableList = this.BaseDbContext.FetchBaseDbLogic().GetDbTableListByConnString(dbInfo.DatabaseName, dbInfo.DatabaseType);
        }

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="dbInfo"></param>
        public DataClassMapper(DbInfo dbInfo, string contextTbls)
        {
            this.BaseDbContext = new BaseDbContext(CreateConnString(dbInfo));
            this.DbInfo = dbInfo;
            this.ContextTbls = contextTbls;
            List<TableClass> tclist = this.BaseDbContext.FetchBaseDbLogic().GetDbTableListByConnString(dbInfo.DatabaseName, dbInfo.DatabaseType);
            int index = 0;
            foreach (var tc in tclist)
            {
                if (string.IsNullOrEmpty(this.ContextTbls) || ("," + this.ContextTbls + ",").IndexOf("," + tc.TableName + ",") > -1)
                {
                    this.TableList.Add(tc);
                }

                index++;
            }
        }

        /// <summary>
        /// 获取连接字符串
        /// </summary>
        /// <param name="dbInfo"></param>
        /// <returns></returns>
        public string CreateConnString(DbInfo dbInfo)
        {
            switch (dbInfo.DatabaseType)
            {
                case "mysql": return "Database='" + dbInfo.DatabaseName + "';Data Source='" + dbInfo.IP + "';User Id='" + dbInfo.UserName + "';Password='" + dbInfo.Password + "';charset='utf8';pooling=true;";
                case "access": return "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dbInfo.IP;
                case "sqlite": return "Data Source=" + dbInfo.IP + ";";
                case "sqlserver": return "Data Source=" + dbInfo.IP + ";Initial Catalog=" + dbInfo.DatabaseName + ";Persist Security Info=True;User ID=" + dbInfo.UserName + ";Password=" + dbInfo.Password;
                case "oracle": return "Data Source=" + dbInfo.IP + ";User Id=" + dbInfo.UserName + ";Password=" + dbInfo.Password + ";";
            }

            return string.Empty;
        }

        /// <summary>
        /// 创建上下文类
        /// </summary>
        /// <returns></returns>
        public string CreateDbContextClass()
        {
            string databaseType = "";
            switch (this.DbInfo.DatabaseType)
            {
                case "mysql": databaseType = "Mysql"; break;
                case "access": databaseType = "OLEDB"; break;
                case "sqlite": databaseType = "SQLite"; break;
                case "sqlserver": databaseType = "SqlServer"; break;
                case "oracle": databaseType = "Oracle"; break;
            }

            string str = string.Empty;
            str += "using System;\r\n";
            str += "using System.Collections.Generic;\r\n";
            str += "using System.Linq;\r\n";
            str += "using System.Text;\r\n";
            str += "using Fdb;\r\n";
            str += "using Fdb.Model;\r\n";
            str += "\r\n";
            str += "namespace Model\r\n";
            str += "{\r\n";
            str += "    public class " + Common.FirstLetterUpper(this.DbInfo.DatabaseName) + "_DbContext : BaseDbContext\r\n";
            str += "    {\r\n";

            int index = 0;
            foreach (TableClass table in this.TableList)
            {
                if (string.IsNullOrEmpty(this.ContextTbls) || ("," + this.ContextTbls.ToLower() + ",").IndexOf("," + table.TableName.ToLower() + ",") > -1)
                {
                    table.TableName = Common.FirstLetterUpper(table.TableName);
                    str += "        /// <summary>\r\n";
                    str += "        /// " + table.TableCNName + "逻辑对象\r\n";
                    str += "        /// </summary>\r\n";
                    str += "        public readonly Logic<" + table.TableName + "> " + table.TableName + " = new Logic<" + table.TableName + ">();\r\n";
                }

                index++;
            }

            str += "        \r\n";
            str += "        /// <summary>\r\n";
            str += "        /// 默认构造方法\r\n";
            str += "        /// </summary>\r\n";
            str += "        public " + Common.FirstLetterUpper(this.DbInfo.DatabaseName) + "_DbContext()\r\n";
            str += "        {\r\n";
            str += "        \r\n";
            str += "        }\r\n";
            str += "        \r\n";
            str += "        /// <summary>\r\n";
            str += "        /// 全局数据库上下文构造方法\r\n";
            str += "        /// </summary>\r\n";
            str += "        /// <param name=\"connectionString\">数据库连接字符串</param>\r\n";
            str += "        public " + Common.FirstLetterUpper(this.DbInfo.DatabaseName) + "_DbContext(string connectionString) : base(connectionString)\r\n";

            str += "        {\r\n";
            //str += "        this.Object.ConnectionString = connectionString;\r\n";
            //str += "        this.Object.DatabaseType = DatabaseType." + databaseType + ";\r\n";

            index = 0;
            foreach (TableClass table in this.TableList)
            {
                if (string.IsNullOrEmpty(this.ContextTbls) || ("," + this.ContextTbls + ",").IndexOf("," + table.TableName.ToLower() + ",") > -1)
                {
                    str += "                this." + table.TableName + ".ConnectionString = connectionString;\r\n";
                    str += "                this." + table.TableName + ".DatabaseType = DatabaseType." + databaseType + ";\r\n";
                }

                index++;
            }

            str += "        }\r\n";
            str += "        \r\n";
            str += "        /// <summary>\r\n";
            str += "        /// 创建所有系统表\r\n";
            str += "        /// </summary>\r\n";
            str += "        /// <returns></returns>\r\n";
            str += "        public ExecuteResult CreateTable()\r\n";
            str += "        {\r\n";
            str += "                ExecuteResult er = new ExecuteResult();\r\n";
            index = 0;
            foreach (TableClass table in this.TableList)
            {
                if (string.IsNullOrEmpty(this.ContextTbls) || ("," + this.ContextTbls.ToLower() + ",").IndexOf("," + table.TableName.ToLower() + ",") > -1)
                {
                    str += "                er = " + table.TableName + ".CreateTable();\r\n";
                    str += "                if (!er.Success) return er;\r\n";
                }

                index++;
            }

            str += "                return er;\r\n";

            str += "        }\r\n";
            str += "    }\r\n";
            str += "}\r\n";
            return str;
        }

        /// <summary>
        /// 创建实体类
        /// </summary>
        /// <param name="tableName">表名称</param>
        /// <returns></returns>
        public string CreateTableClass(string tableName)
        {
            List<FieldClass> fieldList = this.BaseDbContext.FetchBaseDbLogic().GetTblFieldListByConnString(this.DbInfo.DatabaseName, this.DbInfo.DatabaseType, tableName);
            string str = string.Empty;
            str += "using System;\r\n";
            str += "using System.Collections.Generic;\r\n";
            str += "using System.Linq;\r\n";
            str += "using System.Text;\r\n";
            str += "using System.Data;\r\n";
            str += "using Fdb;\r\n";
            str += "using Fdb.Model;\r\n";
            str += "\r\n";
            string tabCnName = tableName;
            foreach (var tab in this.TableList)
            {
                tab.TableName = Common.FirstLetterUpper(tab.TableName);
                if (tab.TableName.ToLower().Equals(tableName.ToLower()))
                {
                    tabCnName = tab.TableCNName;
                    break;
                }
            }

            str += "namespace Model\r\n";
            str += "{\r\n";
            str += "    /// <summary>\r\n";
            str += "    /// " + tabCnName + "\r\n";
            str += "    /// " + DateTime.Now + "\r\n";

            int keyCount = fieldList.Count(p => p.IsPrimaryKey);
            if (keyCount > 1)
            {
                str += "    /// 注：此实体包含多个主键属性[DbKey]，请在对应数据表增加一个组合的字段，再生成实体代码。\r\n";
                str += "    /// 此版本Fdb只支持单字段主键。\r\n";
                str += "    /// 然后在实体代码中手动给组合的字段属性加上[DbKey]特性。\r\n";
            }

            str += "    /// </summary>\r\n";
            str += "    public class " + Common.FirstLetterUpper(tableName) + "\r\n";
            str += "    {\r\n";

            foreach (FieldClass field in fieldList)
            {
                str += "        /// <summary>\r\n";
                str += "        /// " + field.FieldCNName + "\r\n";
                str += "        /// </summary>\r\n";
                if (field.IsPrimaryKey)
                {
                    string dbkey = "        [DbKey]\r\n";
                    if (this.DbInfo.DatabaseType.ToLower().Equals("oracle"))
                    {
                        if (field.FieldTypeName.Equals("decimal"))
                        {
                            dbkey = "        [DbKey(\"SEQ_" + Common.FirstLetterUpper(tableName) + "\",true)] //描述部分对应的是oracle序列，第二参数为true代表代码级别填充主键，false代表由数据表自动填充主键，如触发器完成填充。此处可自行修改！\r\n";
                        }
                    }

                    str += dbkey;
                }

                str += "        public " + field.FieldTypeName + " " + field.FieldName + " { get; set; }\r\n";
            }

            str += "    }\r\n";
            str += "}\r\n";
            return str;
        }
    }
}
